package com.example.apricots.Utils;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

import com.arcsoft.face.ActiveFileInfo;
import com.arcsoft.face.AgeInfo;
import com.arcsoft.face.ErrorInfo;
import com.arcsoft.face.Face3DAngle;
import com.arcsoft.face.FaceEngine;
import com.arcsoft.face.FaceFeature;
import com.arcsoft.face.FaceInfo;
import com.arcsoft.face.GenderInfo;
import com.arcsoft.face.LivenessParam;
import com.arcsoft.face.enums.DetectFaceOrientPriority;
import com.arcsoft.face.enums.DetectMode;
import com.arcsoft.imageutil.ArcSoftImageFormat;
import com.arcsoft.imageutil.ArcSoftImageUtil;
import com.arcsoft.imageutil.ArcSoftImageUtilError;
import com.example.apricots.Common.Contracts;
import com.example.apricots.R;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * 功能:
 * 一、激活引擎
 * 二、获取激活文件信息
 * 三、初始化
 * 四、人脸检测
 * 五、人脸特征提取
 * 六、人脸特征对比
 * 七、活体检测
 * 八、人脸属性检测（年龄/性别/人脸3D角度）
 */
public class ArcFaceUtil extends AppCompatActivity implements View.OnClickListener {

    private static ArcFaceUtil instance;

    public static ArcFaceUtil getInstance() {
        return instance = new ArcFaceUtil();
    }

    private static final String TAG = ArcFaceUtil.class.getSimpleName();
    private int scale = 32;
    private int maxFaceNum = 5; // 如下的组合，初始化的功能包含：人脸检测、人脸识别、RGB活体检测、年龄、性别、人脸3D角度
    private int initMask = FaceEngine.ASF_FACE_DETECT | FaceEngine.ASF_FACE_RECOGNITION | FaceEngine.ASF_LIVENESS | FaceEngine.ASF_AGE | FaceEngine.ASF_IR_LIVENESS | FaceEngine.ASF_FACE3DANGLE | FaceEngine.ASF_GENDER;
    private int Mask = FaceEngine.ASF_AGE | FaceEngine.ASF_GENDER | FaceEngine.ASF_FACE3DANGLE | FaceEngine.ASF_LIVENESS;

    FaceEngine faceEngine;

    Button face_attr_image;
    ImageView iv_face;
    boolean libraryExists = true;
    // Demo 所需的动态库文件
    private static final String[] LIBRARIES = new String[]{
            // 人脸相关
            "libarcsoft_face_engine.so",
            "libarcsoft_face.so",
            // 图像库相关
            "libarcsoft_image_util.so",
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_arc_face_info);

        //getpermission();
        //activeEngine();
        //activeFileInfo();
        //initEngine();
        //detectFace();
        //getfaceFeature();
        Log.e(TAG, "path" + Environment.getExternalStorageDirectory().getPath() + "path1" + Environment.getExternalStorageDirectory().getAbsolutePath());

        face_attr_image = findViewById(R.id.face_attr_image);
        iv_face = findViewById(R.id.iv_face);
        face_attr_image.setOnClickListener(this);
        libraryExists = ChecksoFile(LIBRARIES);
    }

    /**
     * 提取人脸特征
     */
    public void getfaceFeature() {
        Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.face);
        //首先进行人脸检测,检测到了再进行特征提取
        // 原始图像
        //Bitmap originalBitmap = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory().getPath()+"/face.jpg");
        // 获取宽高符合要求的图像
        Bitmap bitmap = ArcSoftImageUtil.getAlignedBitmap(bm, true);
        // 为图像数据分配内存
        byte[] bgr24 = ArcSoftImageUtil.createImageData(bitmap.getWidth(), bitmap.getHeight(), ArcSoftImageFormat.BGR24);
        // 图像格式转换
        int transformCode = ArcSoftImageUtil.bitmapToImageData(bitmap, bgr24, ArcSoftImageFormat.BGR24);
        if (transformCode != ArcSoftImageUtilError.CODE_SUCCESS) {
            Log.i(TAG, "transform failed, code is : " + transformCode);
            return;
        }
        //图像宽度，为4的倍数;   图像高度，在NV21格式下要求为2的倍数,BGR24/GRAY/DEPTH_U16格式无限制；
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();

        List<FaceInfo> faceInfoList = new ArrayList<>();
        int code = faceEngine.detectFaces(bgr24, width, height, FaceEngine.CP_PAF_BGR24, faceInfoList);
        if (code == ErrorInfo.MOK && faceInfoList.size() > 0) {
            Log.i(TAG, "detectFaces, face num is : " + faceInfoList.size());
            FaceFeature faceFeature = new FaceFeature();
            // 在FaceFeature的二进制数组中保存获取到的人脸特征数据
            int extractCode = faceEngine.extractFaceFeature(bgr24, width, height, FaceEngine.CP_PAF_BGR24, faceInfoList.get(0), faceFeature);
            if (extractCode == ErrorInfo.MOK) {
                Log.i(TAG, "extract face feature success");
                //特征提取成功
            } else {
                Log.i(TAG, "extract face feature failed, code is : " + extractCode);
            }

        } else {
            Log.i(TAG, "no face detected, code is : " + code);
        }

    }

    /**
     * 活体检测
     */
    public void LivenessCheck() {
        float rgbThreshold = 0.5f;
        float irThreshold = 0.7f;
        LivenessParam livenessParam = new LivenessParam(rgbThreshold, irThreshold);
        int code = faceEngine.setLivenessParam(livenessParam);
        Log.i(TAG, "setLivenessParam code is : " + code);
    }

    /**
     * 人脸属性检测
     */
    public void FaceParmCheck() {
        Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.face);
        // 原始图像
        //Bitmap originalBitmap = BitmapFactory.decodeFile("filename");
        // 获取宽高符合要求的图像
        Bitmap bitmap = ArcSoftImageUtil.getAlignedBitmap(bm, true);
        // 为图像数据分配内存
        byte[] bgr24 = ArcSoftImageUtil.createImageData(bitmap.getWidth(), bitmap.getHeight(), ArcSoftImageFormat.BGR24);
        // 图像格式转换
        int transformCode = ArcSoftImageUtil.bitmapToImageData(bitmap, bgr24, ArcSoftImageFormat.BGR24);
        if (transformCode != ArcSoftImageUtilError.CODE_SUCCESS) {
            Log.i(TAG, "transform failed, code is : " + transformCode);
            return;
        }
        //图像宽度，为4的倍数;   图像高度，在NV21格式下要求为2的倍数,BGR24/GRAY/DEPTH_U16格式无限制；
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();


        List<FaceInfo> faceInfoList = new ArrayList<>();
        int code = faceEngine.detectFaces(bgr24, width, height, FaceEngine.CP_PAF_BGR24, faceInfoList);
        if (code == ErrorInfo.MOK && faceInfoList.size() > 0) {
            Log.i(TAG, "detectFaces, face num is : " + faceInfoList.size());
            int faceProcessCode = faceEngine.process(bgr24, width, height, FaceEngine.CP_PAF_BGR24, faceInfoList, Mask);
            if (faceProcessCode == ErrorInfo.MOK) {
                Log.i(TAG, "process success");
                //process接口已经检测成功
                getage();
                getgender();
                getface3dangle();

            } else {
                Log.i(TAG, "process failed, code is : " + faceProcessCode);
            }

        } else {
            Log.i(TAG, "no face detected, code is : " + code);
        }

    }

    /**
     * 获取3D角度信息
     * 前提： process 接口调用成功，且combinedMask参数中包含 ASF_FACE3DANGLE 属性
     */
    public void getface3dangle() {
        List<Face3DAngle> face3DAngleList = new ArrayList<>();
        int face3DAngleCode = faceEngine.getFace3DAngle(face3DAngleList);
        // 获取第一个人脸的角度信息，多人脸情况进行循环即可
        if (face3DAngleCode == ErrorInfo.MOK && face3DAngleList.size() > 0) {
            if (face3DAngleList.size() > 0) {
                // 可使用getYaw、getRoll、getPitch等函数获取三维角度
                int yaw = (int) face3DAngleList.get(0).getYaw();
                int roll = (int) face3DAngleList.get(0).getRoll();
                int pitch = (int) face3DAngleList.get(0).getPitch();
                // 查看status
                int status = face3DAngleList.get(0).getStatus();
                Log.i(TAG, "getFace3DAngle, status of the first face is : " + status);
                Log.i(TAG, "getFace3DAngle, yaw of the first face is : " + yaw);
                Log.i(TAG, "getFace3DAngle, roll of the first face is : " + roll);
                Log.i(TAG, "getFace3DAngle, pitch of the first face is : " + pitch);
            } else {
                Log.i(TAG, "no face processed");
            }
        } else {
            Log.i(TAG, "get face3DAngle failed, code is : " + face3DAngleCode);
        }
    }


    /**
     * 获取性别信息
     * 前提： process 接口调用成功，且combinedMask参数中包含 ASF_GENDER 属性
     */
    public void getgender() {
        List<GenderInfo> genderInfoList = new ArrayList<>();
        int genderCode = faceEngine.getGender(genderInfoList);
        if (genderCode == ErrorInfo.MOK) {
            if (genderInfoList.size() > 0) {
                Log.e(TAG, "gender of the first face is : " + genderInfoList.get(0).getGender());
            } else {
                Log.i(TAG, "no face processed");
            }
        } else {
            Log.i(TAG, "get gender failed, code is : " + genderCode);
        }
    }

    /**
     * 获取年龄信息。
     * 前提： process 接口调用成功，且combinedMask参数中包含 ASF_AGE 属性
     */
    public int getage() {
        int age = 0;
        List<AgeInfo> ageInfoList = new ArrayList<>();
        int ageCode = faceEngine.getAge(ageInfoList);
        // 获取第一个人脸的年龄信息，多人脸情况进行循环即可
        if (ageCode == ErrorInfo.MOK && ageInfoList.size() > 0) {
            if (ageInfoList.size() > 0) {
                Log.e(TAG, "age of the first face is : " + ageInfoList.get(0).getAge());
                age = ageInfoList.get(0).getAge();

            } else {
                Log.i(TAG, "no face processed");
            }
        } else {
            Log.i(TAG, "get age failed, code is : " + ageCode);
        }
        return age > 0 ? age : -1;
    }

    /**
     * 人脸检测，为后面的人脸特征提取做铺垫
     */
    public void detectFace() {
        Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.face);
        // 原始图像
        //Bitmap originalBitmap = BitmapFactory.decodeFile("filename");
        // 获取宽高符合要求的图像
        Bitmap bitmap = ArcSoftImageUtil.getAlignedBitmap(bm, true);
        // 为图像数据分配内存
        byte[] bgr24 = ArcSoftImageUtil.createImageData(bitmap.getWidth(), bitmap.getHeight(), ArcSoftImageFormat.BGR24);
        // 图像格式转换
        int transformCode = ArcSoftImageUtil.bitmapToImageData(bitmap, bgr24, ArcSoftImageFormat.BGR24);
        if (transformCode != ArcSoftImageUtilError.CODE_SUCCESS) {
            Log.i(TAG, "transform failed, code is : " + transformCode);
            return;
        }
        //图像宽度，为4的倍数;   图像高度，在NV21格式下要求为2的倍数,BGR24/GRAY/DEPTH_U16格式无限制；
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();

        List<FaceInfo> faceInfoList = new ArrayList<>();
        int code = faceEngine.detectFaces(bgr24, width, height, FaceEngine.CP_PAF_BGR24, faceInfoList);
        if (code == ErrorInfo.MOK && faceInfoList.size() > 0) {
            Log.i(TAG, "detectFaces, face num is : " + faceInfoList.size());
        } else {
            Log.i(TAG, "no face detected, code is : " + code);
        }
    }

    /**
     * 初始化引擎
     */
    public void initEngine() {

        faceEngine = new FaceEngine();
        int code = faceEngine.init(getApplicationContext(),
                DetectMode.ASF_DETECT_MODE_VIDEO,
                DetectFaceOrientPriority.ASF_OP_0_ONLY,
                scale,
                maxFaceNum,
                initMask);
        if (code != ErrorInfo.MOK) {
            Toast.makeText(this, "init failed, code is : " + code, Toast.LENGTH_SHORT).show();
        } else {
            Log.i(TAG, "init success");

        }
    }

    /**
     * 申请READ_PHONE_STATE和CAMERA权限
     */
    public void getpermission() {
        int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE);
        int permissionCheck1 = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);

        if (permissionCheck != PackageManager.PERMISSION_GRANTED || permissionCheck1 != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, 1);
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 1);
        } else {
            //TODO
            //Toast.makeText(this,"权限申请失败",Toast.LENGTH_SHORT).show();
        }
    }

    public void activeFileInfo(Context context) {
        ActiveFileInfo activeFileInfo = new ActiveFileInfo();
        int code = FaceEngine.getActiveFileInfo(context, activeFileInfo);
        if (code == ErrorInfo.MOK) {
            Log.i(TAG, "activeFileInfo is : " + activeFileInfo.toString());
        } else {
            Log.i(TAG, "getActiveFileInfo failed, code is : " + code);
        }
    }

    /**
     * 用于在线激活SDK,需要联网
     */
    public void activeEngine(Context context) {
        int activecode = FaceEngine.activeOnline(context, Contracts.APP_ID, Contracts.SDK_KEY);
        if (activecode == ErrorInfo.MOK) {
            Log.i(TAG, "activeOnline success");
        } else if (activecode == ErrorInfo.MERR_ASF_ALREADY_ACTIVATED) {
            Log.i(TAG, "already activated");
        } else {
            Log.i(TAG, "activeOnline failed, code is : " + activecode);
        }
    }

    /**
     * 检查能否找到动态链接库，如果能找到才进行下一步
     *
     * @param libraries 需要的动态链接库
     * @return 动态库是否存在
     */
    public boolean ChecksoFile(String[] libraries) {
        File dir = new File(getApplicationInfo().nativeLibraryDir);
        File[] files = dir.listFiles();
        if (files == null || files.length == 0) {
            return false;
        }
        List<String> libnamelist = new ArrayList<>();
        for (File file : files) {
            libnamelist.add(file.getName());
        }
        boolean exist = true;
        for (String library : libraries) {
            exist &= libnamelist.contains(library);
        }
        return exist;
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.face_attr_image:
                jumptofaceattrimage();
        }
    }

    //默认已激活引擎
    public void jumptofaceattrimage() {
        //首先检查动态链接库文件是否存在
        if (!libraryExists) {
            Toast.makeText(this, "so文件不存在", Toast.LENGTH_SHORT).show();
        }
        // startActivity(new Intent(this, FaceAttrVideo.class));
        //detectFace();
        //getfaceFeature();
        //LivenessCheck();
        FaceParmCheck();
    }

}
